package pumpkin.word;

import java.util.LinkedList;
import java.util.Queue;

public class TokenSource {
	String src;
	int index = 0;
	private Queue<Token> tokens = new LinkedList<Token>();

	public boolean isEnd() {
		if (index >= src.length()) {
			return true;
		}
		return false;
	}

	public TokenSource(String src) {
		this.src = src;
	}

	public void pushBack(Token tk) {
		if (tk.getType() != TokenType.EOF) {
			tokens.add(tk);
		}
	}

	public Token next() {
		if (!tokens.isEmpty()) {
			return tokens.poll();
		}
		if (index >= src.length()) {
			return EOF.instance();
		}

		for (; index < src.length();) {
			char c = src.charAt(index);
			if (c == ' ') {
				index++;
				continue;
			} else {
				break;
			}
		}
		char c = src.charAt(index);
		if (c == '+') {
			index++;
			return new SymbolToken("+");
		}
		if (c == '-') {
			index++;
			return new SymbolToken("-");
		}
		if (c == '*') {
			index++;
			return new SymbolToken("*");
		}
		if (c == '/') {
			index++;
			return new SymbolToken("/");
		}
		if (c == '(') {
			index++;
			return new SymbolToken("(");
		}
		if (c == ')') {
			index++;
			return new SymbolToken(")");
		}

		if (isDigit(c)) {
			StringBuilder strb = new StringBuilder();
			strb.append(c);
			for (index = index + 1; index < src.length(); ++index) {
				c = src.charAt(index);
				if (validNum(c)) {
					strb.append(c);
				} else {
					break;
				}

			}
			return new Num(strb.toString());
		}
		if (isAlpha(c) || c == '_') {
			StringBuilder strb = new StringBuilder();
			strb.append(c);
			for (index = index + 1; index < src.length(); ++index) {
				c = src.charAt(index);
				if (validId(c)) {
					strb.append(c);
				} else {
					break;
				}
			}
			return new Iden(strb.toString());
		}
		return null;
	}

	private boolean validId(char c) {
		if (isAlpha(c)) {
			return true;
		}
		if (isDigit(c)) {
			return true;
		}
		if (c == '_') {
			return true;
		}
		return false;
	}

	private boolean validNum(char c) {
		if (isDigit(c)) {
			return true;
		}
		if (c == '.') {
			return true;
		}
		return false;
	}

	private boolean isAlpha(char c) {
		if (c >= 'a' && c <= 'z') {
			return true;
		}
		if (c >= 'A' && c <= 'Z') {
			return true;
		}
		return false;
	}

	private boolean isDigit(char c) {
		if (c >= '0' && c <= '9') {
			return true;
		}
		return false;
	}
}
